/* 
 * File:   TempMap.h
 * Author: dechow
 *
 * Created on 12. Juli 2011, 14:46
 */

#ifndef TEMPMAP_H
#define	TEMPMAP_H

//#include "timestamp.h"
//#include "Basics_vector.h"
//#include "Basics.h"
# define PRECISION 15
using namespace std;

class inp_tempmap_aggr
{
public:
	tempmap <string,double> *source;
	string type_of_aggreg;
	double boundary_constraint;
	int minpoints;
	vector <string> variables;

	inp_tempmap_aggr(){;}
	inp_tempmap_aggr(tempmap <string,double> *isource,
		string itype_of_aggreg,
		double iboundary_constraint,
		int iminpoints,
		vector <string> &ivariables)
	{
		source=isource;
		type_of_aggreg=itype_of_aggreg;
		boundary_constraint=iboundary_constraint;
		minpoints=iminpoints;
		variables=ivariables;
	}
	inp_tempmap_aggr(string itype_of_aggreg)
	{
		type_of_aggreg=itype_of_aggreg;
	}
	~inp_tempmap_aggr(){;}
};



template <typename T, typename U>  class tempmap
    {

        vector <time_intervall> time;
        map <T,vector<U> > val;
            U nodata;
            U nulldata;	
           int set_insert_a_row_entry (int row,tempmap <T,U> &source,int source_row)
                {
                    typename map <T, vector<U> >::const_iterator it;
                    if(this->check_for_keys(source.get_valkeys())) err::err3("tempmap set_insert_a_row_entry: source keys are not all in this tempmap");
                    if(source.check_for_keys(this->get_valkeys())) err::err3("tempmap set_insert_a_row_entry: this valkeys are not all in source");
                    source.check_myself();
                    this->check_myself();

                    this->time.insert(this->time.begin()+row,source.get_time_intervall(source_row));
                    for(it=val.begin();it!=val.end();it++){
                            this->val[it->first].insert(this->val[it->first].begin()+row,source.get_val(it->first,source_row));
                    }
                    return check_myself();
                 }
   int set_insert_a_row_entry(time_intervall tt,map<T,U> source,int row)
    {
            // inserts a complete new row
            // input is the new time intervall and the row
            //Attention: a variable of source not element of this tempmap will not be considered
            //Attention: a variable of this tempmap not found in source will be filled with nodata

            typename map <T, vector <U> >::const_iterator it;
            this->time.insert(this->time.begin()+row,tt);
            for(it=val.begin();it!=val.end();it++){
                    if(source.find(it->first)==source.end())
                    {
                            this->val[it->first].insert(this->val[it->first].begin()+row,this->nodata);
                    }
                    else
                    {
                            this->val[it->first].insert(this->val[it->first].begin()+row,source[it->first]);
                    }
            }
            this->check_myself();
            return 0;
    }
  int set_replace_vals_from_map(int row,map<T,U> source)
    {
            typename map <T,U>::const_iterator it;
            for(it=source.begin();it!=source.end();it++)
            {
                    this->set_val(it->first,row,it->second);
            }
            return 0;
    }
public:
	string intervall_mode;
	int multipli;
	double dur;
     
tempmap(U inulldata,U inodata,string iintervall_mode, int imultipli,double idur)
{
        nodata=inodata;
        nulldata=inulldata;
        this->intervall_mode=iintervall_mode;
        multipli=imultipli;
        dur=idur;
}

tempmap(tempmap <T,U> *source)
{
    this->dur=source->dur;
    this->intervall_mode=source->intervall_mode;
    this->multipli=source->multipli;
    this->nodata=source->get_nodata();
    this->nulldata=source->get_nulldata();
}
//template <typename T,typename U>
//tempmap tempmap(tempmap <T,string> *source)
//{
//    this->dur=source->dur;
//    this->intervall_mode=source->intervall_mode;
//    this->multipli=source->multipli;
//    this->nodata=source->get_nodata();
//    this->nulldata=source->get_nulldata();
//}
tempmap(){;}

~tempmap(){;}

//tempmap tempmap()
//{;
//}
//tempmap ~tempmap()
//{
//	;
//}
//out
int print_in_file_simple_style_without_mydate(string root,string name,string suffix)
{
        int timencols,valncols;
        unsigned int row;
        typename map < T,vector<U> > ::const_iterator it;
        string file=root+name+suffix;

        ofstream out(file.c_str());
        out<<setprecision(PRECISION);
        if(!out){ 
                err::err2("tempmap print_in__file: Coud_not_open_file: "+file);
                return 1;
        }
        timencols=3;
        valncols=val.size();
        out<<timencols+valncols<<endl;
        out<<"year"<<"\t"<<"mon"<<"\t"<<"day"<<"\t";
        for(it=val.begin();it!=val.end();it++){
                out<<it->first<<"\t";
        }
        out<<endl;
        for(row=0;row<time.size();row++){
                out<<time[row].get_start().get_year()<<"\t"<<time[row].get_start().get_mon()<<"\t"<<(double)time[row].get_start().get_day()<<"\t";
                for(it=val.begin();it!=val.end();it++){
                        out<<val[it->first][row]<<"\t";
                }
                out<<endl;
        }
        return 0;
}
int print_in_file_simple_style_with_mydate(string root,string name,string suffix) 
{
        int timencols,valncols;
        unsigned int row;
        typename map < T,vector<U> > ::const_iterator it;
        string file=root+name+suffix;

        ofstream out(file.c_str());
        out<<setprecision(PRECISION);
        if(!out){ 
                err::err2("tempmap print_in__file: Coud_not_open_file: "+file);
                return 1;
        }
        timencols=5;
        valncols=val.size();
        out<<timencols+valncols<<endl;
        out<<"startmydate"<<"\t"<<"endmydate"<<"\t"<<"year"<<"\t"<<"mon"<<"\t"<<"day"<<"\t";
        for(it=val.begin();it!=val.end();it++){
                out<<it->first<<"\t";
        }
        out<<endl;
        for(row=0;row<time.size();row++){
                out<<time[row].get_start().get_mydate()<<"\t"<<time[row].get_end().get_mydate()<<"\t";
                out<<time[row].get_start().get_year()<<"\t"<<time[row].get_start().get_mon()<<"\t"<<time[row].get_start().get_day()<<"\t";
                for(it=val.begin();it!=val.end();it++){
                        out<<val[it->first][row]<<"\t";
                }
                out<<endl;
        }
        return 0;
}
int print_in_file_start_end_style_without_mydate(string root,string name,string suffix)
{
        int timencols,valncols;
        unsigned int row;
        typename map < T,vector< U > > ::const_iterator it;
        string file=root+name+suffix;

        ofstream out(file.c_str());
        out<<setprecision(PRECISION);
        if(!out){ 
                err::err2("tempmap print_in__file: Coud_not_open_file: "+file);
                return 1;
        }
        timencols=6;
        valncols=val.size();
        out<<timencols+valncols<<endl;
        out<<"startyear"<<"\t"<<"startmon"<<"\t"<<"startday"<<"\t"<<"endyear"<<"\t"<<"endmon"<<"\t"<<"endday"<<"\t";
        for(it=val.begin();it!=val.end();it++){
                out<<it->first<<"\t";
        }
        out<<endl;
        for(row=0;row<time.size();row++){
                out<<time[row].get_start().get_year()<<"\t"<<time[row].get_start().get_mon()<<"\t"<<time[row].get_start().get_day()<<"\t";
                out<<time[row].get_end().get_year()<<"\t"<<time[row].get_end().get_mon()<<"\t"<<time[row].get_end().get_day()<<"\t";
                for(it=val.begin();it!=val.end();it++){
                        out<<val[it->first][row]<<"\t";
                }
                out<<endl;
        }
        return 0;
}
int print_in_file_start_end_style_with_mydate(string root,string name,string suffix) 
{
        int timencols,valncols;
        unsigned int row;
        typename map < T,vector<U> > ::const_iterator it;
        string file=root+name+suffix;
        double te;

        ofstream out(file.c_str());
        out<<setprecision(PRECISION);
        if(!out){ 
                err::err2("tempmap print_in__file: Coud_not_open_file: "+file);
                return 1;
        }
        timencols=8;
        valncols=val.size();
        out<<timencols+valncols<<endl;
        out<<"startmydate"<<"\t"<<"endmydate"<<"\t"<<"startyear"<<"\t"<<"startmon"<<"\t"<<"startday"<<"\t"<<"endyear"<<"\t"<<"endmon"<<"\t"<<"endday"<<"\t";
        for(it=val.begin();it!=val.end();it++){
                out<<it->first<<"\t";
        }
        out<<endl;
        for(row=0;row<time.size();row++){
                te=time[row].get_end().get_mydate();
                out<<(double)time[row].get_start().get_mydate()<<"\t"<<time[row].get_end().get_mydate()<<"\t";
                out<<time[row].get_start().get_year()<<"\t"<<time[row].get_start().get_mon()<<"\t"<<time[row].get_start().get_day()<<"\t";
                out<<time[row].get_end().get_year()<<"\t"<<time[row].get_end().get_mon()<<"\t"<<time[row].get_end().get_day()<<"\t";
                for(it=val.begin();it!=val.end();it++){
                        out<<val[it->first][row]<<"\t";
                }
                out<<endl;
        }
        return 0;
}
//set
int set_val(T id, unsigned int row, U value)
{
        //just replaces some old value
        if (val.find(id)==val.end()) {err::err2("tempmap set_val: key not found");return 1;}
        if((row<0)||(row>=val[id].size()))  {err::err2("tempmap set_val: row out of range");return 1;}
        val[id][row]=value;
        return 0;
}
int set_time_intervall(unsigned int row, time_intervall &source)
{
        //just replaces zum old timeintervall
        time[row]=source;
        return check_myself();
}
int set_clear()
{
        time.clear();
        val.clear();
        return 0;
}
int set_read_from_file(string root, string name,string suffix,string iintervallmode,int imultipli, double dur)
{
        string file;

                string time_descript;
                T val_descript;
                vector<string> time_id;
        vector<T> val_id;
        vector<U> dummy;
                vector<U> nullvector;
        double startmydate,endmydate;
                time_intervall date_intervall;
        int locncols,col;
                int timencols;
        timestamp startdate;
                timestamp enddate;
                int flag;
                int dummy_int;
                double dummy_double;
                //Variablen setzen
                multipli=imultipli;
                intervall_mode=iintervallmode;
                char char_dummy;
                int year,mon;
                double day;


        file=root+name+suffix;
        //clear
        time.clear();
        val.clear();
        //start to read
        ifstream in(file.c_str());
                if(!in){ 
                        err::err2("tempmap read_from_file: File does not exist:"+file);
                        return 1;
                }
                in>>locncols;
                in>>time_descript;
                // reads first entry and concludes about structure of temporal information
                //flag 0: startyear startmon startday endyear endmon endday
                //flag 1: year mon day
                //flag 2: startmy_date endmy_date
                if (time_descript=="startyear") {
                        flag=1;
                        timencols=6;
                }
                else if(time_descript=="year") {
                        flag=0;
                        timencols=3;
                }
                else if(time_descript=="startmydate"){
                        flag=2;
                        timencols=3;
                }
                else err::err3("tempmap read_from_file: headers of file are not correct.");


                time_id.push_back(time_descript);

        for(col=1;col<timencols;col++)
                {
                        in>>time_descript;
            time_id.push_back(time_descript);
                }
                if(flag==2){
                        if (time_id[timencols-1]=="year"){	
                                flag=2;
                                for(col=timencols;col<timencols+2;col++){
                                        in>>time_descript;
                                        time_id.push_back(time_descript);
                                }
                                timencols=timencols+2;
                        }
                        else if (time_id[timencols-1]=="startyear"){	
                                flag=3;
                                for(col=timencols;col<timencols+5;col++){
                                        in>>time_descript;
                                        time_id.push_back(time_descript);
                                }
                                timencols=timencols+5;
                        }
                        else err::err3("tempmap read_from_file: Strange header in file: "+file);
                }
                locncols=locncols-timencols;
                dummy.resize(locncols);
        for(col=0;col<locncols;col++)
                {

                        in>>val_descript;
            val_id.push_back(val_descript);
                        val[val_id[col]]=nullvector;
                }
        while(!in.eof())
           {
               if(flag==0) {
                                   in>>year>>mon>>day;
                                   startdate.set(year,mon,day);
                                   date_intervall.set_start_zus(startdate,intervall_mode);
                                   date_intervall.set_end_zus(intervall_mode,multipli,dur);
                           }
                           else if(flag==1) { //startdate and enddate are available
                                    in>>year>>mon>>day;
                                    startdate.set(year,mon,day);
                                        in>>year>>mon>>day;
                                    enddate.set(year,mon,day);
                                        date_intervall.set(startdate,enddate);
                           }
                           else if(flag==2){
                                   in>>startmydate>>endmydate;
                                   in>>dummy_int>>dummy_int>>dummy_double;
                                   startdate.set(startmydate);
                                   enddate.set(endmydate);
                                   date_intervall.set(startdate,enddate);
                           }
                            else if(flag==3){
                                   in>>startmydate>>endmydate;
                                   in>>dummy_int>>dummy_int>>dummy_double;
                                   in>>dummy_int>>dummy_int>>dummy_double;	
                                   startdate.set(startmydate);
                                   enddate.set(endmydate);
                                   date_intervall.set(startdate,enddate);
                           }
                           time.push_back(date_intervall);
                           col=0;
                           if(!in.eof()){
                                        do{
                                                 in>>dummy[col];
                                                 val[val_id[col]].push_back(dummy[col]); 
                                                 col++;
                                        }
                                        while((!in.eof())&&(col<locncols));
                                }
                           if(!in.eof())in>>char_dummy;
                           if(!in.eof())in>>char_dummy;
                           if(!in.eof())in>>char_dummy;
                           if(!in.eof())in.seekg(-3,ios::cur);else cout<<"end of file#####";

        }	
                return this->check_myself();
}
int set_order()
{
    tempmap ersatz(this->nulldata,this->nodata,this->intervall_mode,this->multipli);
    unsigned int row;
    int found;
    time_intervall real_big_date;

    real_big_date=Basics_vector::maxval(this->time);
    real_big_date.set_move(real_big_date.get_dur()+10);
    for(row=0;row<this->time.size();row++){
        found=Basics_vector::minvalpos(this->time);
        ersatz.push_back(found,*this);
        this->time[found]=real_big_date;
    }
    this->time=ersatz.time;
            this->val=ersatz.val;
    return 0;
}
int push_back(int found,tempmap &cop)
{
    time.push_back(cop.time[found]);
    typename map< T,vector<U> >::const_iterator it;
    for(it=cop.val.begin();it!=cop.val.end();it++){
        this->val[it->first].push_back(cop.val[it->first][found]);
    }
    return 0;
}
int set_an_empty_tempmap(tempmap *source, vector < T > keys)
{
        //check if tempmap is empty
        if ((this->time.size()>0)||(this->val.size()>0)){
                err::err3("tempmap set_an_empty_tempmap: Tempmap is not empty, but it has to be");
                return 1;
        }

        Basics_vector::push_back_vector(this->point_time(),source->point_time());
        this->set_key(keys);
        this->intervall_mode=source->get_intervallmode();
        this->multipli=source->get_multipli();
        this->dur=source->get_dur();
        return 0;

}
int set_an_empty_tempmap(timestamp begin_date,timestamp end_date,double dur,vector<T> &val_id)
{
        time_intervall du_ti;
        vector <U> dummy_U_vect;
        int dec;
        unsigned int col;
        this->time.clear();
        this->val.clear();
        //2.1 SSet first Intervall
                du_ti.set_start_zus(begin_date,intervall_mode);
                du_ti.set_end_zus(intervall_mode,multipli,dur);
                //2.2 add intervalls
                dec=0;
                do{
                        this->time.push_back(du_ti);
                        if (du_ti.contains(end_date)) dec=1;
                        if(dec==0) du_ti.set_subsequent(du_ti,this->intervall_mode,this->multipli);
                }while(dec!=1);
                //2.3 generate val columns of val_id and fill it with nodata
                for (col=0;col<val_id.size();col++){
                                val[val_id[col]]=dummy_U_vect;
                                val[val_id[col]].assign(this->time.size(),nodata);
                }
        return this->check_myself();
}
int set_insert_a_row_entry (int row,tempmap <T,U> &source,int source_row,time_intervall timesubstitute)
{
        typename map <T, vector<U> >::const_iterator it;
        if((unsigned int) this->check_for_keys(source.get_valkeys())<source.get_valkeys().size()) err::err3("tempmap set_insert_a_row_entry: source keys are not all in this tempmap");
        //if(source.check_for_keys(this->get_valkeys())) err::err3("tempmap set_insert_a_row_entry: this valkeys are not all in source");
        source.check_myself();
        this->check_myself();

        this->time.insert(this->time.begin()+row,timesubstitute);
        for(it=val.begin();it!=val.end();it++){
                this->val[it->first].insert(this->val[it->first].begin()+row,source.get_val(it->first,source_row));
        }
        return check_myself();
}
int set_insert_or_replace_entry(time_intervall tt,map<T,U> &source)
{
        // inserts a row entry into a tempmap, uses tt to find the position in tempmap
        // if there is already a time intervall the values will be replaced by source
        // gives an error if there is just an overlapping 

        int dec=0;
        unsigned int row=0;
        unsigned int pre=Basics_vector::find_precursor_pos_in_ordered_vector(time,tt);
        unsigned int suc=Basics_vector::find_successor_pos_in_ordered_vector(time,tt);
        //there is a timeintervall equal to tt
        if(this->time.size()<1){
                set_insert_a_row_entry(tt, source,0);
                return 0;
        }
        if((pre==suc)&&(pre<this->time.size()))
        {
                this->set_replace_vals_from_map(pre,source);
                return 0;
        }
        // tt is smaller than any time_intervall
        if((pre==time.size())&&(suc==0))
        {
                this->set_insert_a_row_entry(tt,source,0);
                return 0;
        }
        // tt is bigger than any
        if ((suc==time.size())&&(pre==time.size()-1))
        {
                this->set_insert_a_row_entry(tt,source,time.size());
                return 0;
        }
        // tt is in between
        if((suc<time.size()-1)&&(pre+1==suc))
        {
                this->set_insert_a_row_entry(tt,source,suc);
                return 0;
        }	

        err::err3("	tempmap set_insert_or_replace_entry: entry can not be inserted or used to replace");
        return 1;
}
int set_delete_a_row_entry(int row)
{
        typename map <T, vector<U> >::const_iterator it;
        this->time.erase(this->time.begin()+row);
        for(it=val.begin();it!=val.end();it++){
                this->val[it->first].erase(this->val[it->first].begin()+row);
        }
        return this->check_myself();
}
int set_delete_rows_with_specific_value (U &delval)
{
        int row;
        int dec=0;
        typename map < T,vector< U > >::const_iterator it;
         row=this->time.size();
         do{
                dec=0;
                row--;
                for(it=this->val.begin();it!=this->val.end();it++){
                        if(delval!=val[it->first][row]) dec++;
                }
                if(dec==0) {
                        this->set_delete_a_row_entry(row);
                }                                                                                                                                                                   
         }
         while(row>0);
         return this->check_myself();
}
int set_aggregate_by_linear_interp_from_tempmap( inp_tempmap_aggr *aggr)
{
        timestamp begin_date,end_date;
        time_intervall du_ti;
        unsigned int row;
        vector <pair <T,U> > vec_val;

        // Test 
        if ((aggr->type_of_aggreg!="mean")&&(aggr->type_of_aggreg!="mean")) {
                err::err3("Inp_measurements::set_input_from_inp_measurements: aggr is empty");
                return 1;
        }

        //1. begin_date and end_endate from source
        begin_date=aggr->source->get_time_intervall(0).get_mid();
        end_date=aggr->source->get_time_intervall(aggr->source->get_size()-1).get_mid();
        //2. check if source contains variables defined in aggr
        if ((aggr->variables.size())==0) aggr->variables=aggr->source->get_valkeys();
        else{
                if (aggr->source->check_for_keys(aggr->variables))err::err3("tempmap accumulate_by_linear_interpolation: keys you want to have are not within tempmap");
        }

        //3. build a discretisation in dependence on begin_date and end_date with self checking
                this->set_an_empty_tempmap(begin_date,end_date,dur,aggr->variables);
        //4. Make a vector of pairs with key_id and vals(nodata)
                for (row=0;row<aggr->variables.size();row++){
                vec_val.push_back(make_pair(aggr->variables[row],nodata));
        }		
        //5. Loop over the target time intervalls
                for(row=0;row<this->time.size();row++){
                        aggr->source->get_aggregate_of_one_timeintervall_by_linear_interpolation(this->time[row],aggr->type_of_aggreg,aggr->minpoints,aggr->boundary_constraint,vec_val);
                        Basics_vmap::set_vals_from_row_vector(this->val,vec_val,row);
                }
        //6. check
                check_myself();
        //7. eventually delete those rows with nodata
                set_delete_rows_with_specific_value (nodata);
                return 0;
}
int set_key(T key)
{
        //sets new key and fills it with zero
        if(this->check_for_keys(key)){
                vector<U> nullvect;
                this->val[key]=nullvect;
                this->val[key].assign(this->time.size(),nodata);
                return this->check_myself();
        }
        return 1;
}
int set_delete_key(T key)
{
        typename map <T,vector<U> >::iterator it;
        if(!this->check_for_keys(key)){
                it=this->val.find(key);
                this->val.erase(it);
                return this->check_myself();
        }
        err::err2("tempmap set_delete_key: The tempmap has no vector with the key");
        return 1;
}
int set_key (vector <T> keys)
{
        //sets new key vectors and fills them with zero
        unsigned int row;
        for(row=0;row<keys.size();row++)
        {
                this->set_key(keys[row]);
        }
        return 0;
}
int set_key_empty(T key)
{
        // !!!! ACHTUNG diese Methode widerspricht den Grunds�tzen einer tempmap
        if(this->check_for_keys(key)){
                vector<U> nullvect;
                this->val[key]=nullvect;
                return 0;
        }
        return 1;
}
 /**
  * 
  * @param key (identifier of variable
  * @param ti (time_intervall)
  * @param wert (value that should be added
  * @return 0 if tempmap is ok
  * @descr if the time inetrvall is larger than time_intervall in the tempmap a value and a time_intervall is added
  * all other variables get a "nodata" for this new time intervall
  * @descr if the time intervall is equal the last time_intervall in tempmap
  * then just the old value is replaced by the new one
  */
int set_push_back_val(T key,time_intervall &ti,U wert)
 {
    if (this->check_for_keys(key)){
        err::err3("tempmap set_push_back_val: No such key in this tempmap");
    }
    int row=this->val[key].size();
   typename map <T,vector < U > > ::const_iterator it;
    
    if(this->get_last_time_intervall().get_end()==ti.get_start())
    {
        this->time.push_back(ti);
        for(it=this->val.begin();it!=this->val.end();it++){
            if(it->first==key){
                this->val[key].push_back(wert);
            }
            else{
                if(this->val[it->first].size()==row) {
                    this->val[it->first].push_back(nodata);
                }
            }
        }
    }
    else
    {
        if (this->get_last_time_intervall()==ti){
            this->set_val(key,this->get_size()-1,wert);
        }
        else{
            err::err3("tempmap set_push_back_val: Strange_new timeintervall to add");
        }
    }
    
    
   

    return check_myself();
 }
//get
// primary gets
vector <T> get_valkeys()
{
        vector<T> keys;
        Basics_map::get_keys(val,keys);
        return keys;
}
string get_intervallmode()	const
{
        return this->intervall_mode;
}

int get_multipli() const
{
        return this->multipli;
}

double get_dur() const
{
        return dur;
}

timestamp get_start()
{
        if (this->time.size()==0) err::err3 ("tempmap get_end:tempmap has no valid timeseries");
        return this->time[0].get_start();
}

timestamp get_end()
{
        if (this->time.size()==0) err::err3 ("tempmap get_end:tempmap has no valid timeseries");
        return this->time[this->time.size()-1].get_end();
}

time_intervall get_time_intervall(unsigned int a)
{
        //returns the time_intervall assoziated with a row_id a
        if((a>=time.size())||(a<0)){
                 err::err3("tempmap.h::get_time_intervall: row identifier out of range.");
                 return time[0];
        }
        return time[a];
}

time_intervall get_last_time_intervall()
{
        //returns the last time_intervall
        if (time.size()==0){
                err::err3("tempmap get_last_time_intervall::tempmap is empty");
        }
        return get_time_intervall(time.size()-1);
}

U get_val(T id, unsigned int row) 
{
        if(val.find(id)==val.end()) {err::err2("tempmap get_val: key not found");return nodata;}
        if((row<0)||(row>=val[id].size()))  {err::err2("tempmap get_val: row out of range");return nodata;}
        return val[id][row];
}

U get_nodata ()
{
        return nodata;
}

U get_nulldata ()
{
        return nulldata;
}

unsigned int get_row_from_time_intervall (time_intervall &ti)
{
        //returns the row if ti matches one time_intervall in this tempmap
        // otherwise it returns the size of time
        int row;
        if (this->time.size()<1) {
                err::err3("tempmap get_row_from_time_intervall: The tempmap is empty!");
        }
        row=Basics_vector::find_position_of_object(this->time,ti);
        return (unsigned int) row;

}

unsigned int get_row_of_surrounding_time_intervall(time_intervall &ti)
{
        int row=-1;
        int dec=0;
        if (this->time.size()<1) {
                err::err3("tempmap get_row_from_time_intervall: The tempmap is empty!");
        }
        do{
                if (this->time[row].contains(ti))  {dec=1;}
                row++;
        }
        while((dec==0)&&(row<this->time.size()));
        if (dec==1) return row;
        return time.size();
}

unsigned int  get_size() const
{

        return time.size();
}

int  get_number_of_valid_data_points(const int a,const int b,const T id)
{
        int row;
        int count=0;
        this->check_myself();
        if(a>b) return 0;
        for(row=a;row<=b;row++){
                if(this->val[id][row]!=nodata) count++;
        }
        return count;

}

int  get_number_of_midpoints_within_an_intervall(const time_intervall &ti)
{
        int row=0;
        int dec=0;
        timestamp ts;
        do{
                if (ti.contains(this->time[row].get_mid())) dec++;
                        row++;
        }while(this->time[row].get_start()>ti.get_end());
        return dec;
}

int  get_pos_of_first_overlapping_intervall(time_intervall ti)
{
        //finds the pos of the time intervall that 
        // 1. Overlaps with ti
        // 2. Starts earlier or at the same time as ti
        //Returns size of this tempmap if conditions (1.,2.) could not be fullfilled
        // otherwise returns the position of the respective time_intervall
        unsigned int row=0;
        if (this->time.size()<1)err::err3("tempmap get_pos_of_smaller_equal_ti: This tempmap is empty");
        while((!(this->time[row].overlap(ti)))&&(row<=this->get_size()-1))
        {
                 row++;
        }
        if (row>this->get_size()-1)return row;
        if (this->time[row].get_start()<=ti.get_start())return row;
        return this->get_size();
}

int  get_pos_of_last_overlapping_intervall(time_intervall ti)
{
        //finds the pos of the time intervall that 
        // 1. Overlaps with ti
        // 2. Ends later or at the same time as ti
        //Returns size of this tempmap if conditions (1.,2.) could not be fullfilled
        // otherwise returns the position of the respective time_intervall

        if (this->time.size()<1)err::err3("tempmap get_pos_of_smaller_equal_ti: This tempmap is empty");
        unsigned int row=this->time.size()-1;

        while(!(this->time[row].overlap(ti))&&(row!=0))
        {
                 row--;
        }
        if ((row==0)&&!(this->time[row].overlap(ti)))return this->get_size();
        if (this->time[row].get_end()>=ti.get_end())return row;
        return this->get_size();
}

int  get_next_loweq_valid_data_midpoint(const timestamp &ts,unsigned int &rowid,const T id)
{
        unsigned int row=0;
        int dec=0;
        this->check_myself();
        if (time.size()<0) {
                err::err3("tempmap get_next_loweq_valid_data_midpoint: The source tempmap is empty");
                return 1;
        }
        row=this->time.size();
        do{
                if (row==0) return 1;
                row--;

        }
        while((this->time[row].get_mid()>ts)||(val[id][row]==nodata));

        rowid=row;
        return 0;
}

int  get_next_upeq_valid_data_midpoint(const timestamp &ts,unsigned int &rowid,const T id)
{
        int row=-1;
        int dec=0;
        this->check_myself();
        if (time.size()==0) {
                err::err3("tempmap get_next_upeq_valid_data_midpoint: The source tempmap is empty");
                return 1;
        }
        do{
                row++;
                if(row==time.size()) {
                        return 1;
                }
        }
        while((this->time[row].get_mid()<ts)||(val[id][row]==nodata));
        rowid=row;
        return 0;
}

U get_linear_interpolated_value_from_midpoints(timestamp &ts,const T col_id)
{
        unsigned int row_low,row_high;
        int dec=0;
        U yges,yges1,yges2;
        double tges,tlow;
        dec=dec+this->check_myself();
        //1. Test if values are different from nodata
        dec=dec+this->get_next_loweq_valid_data_midpoint(ts,row_low,col_id);
        dec=dec+this->get_next_upeq_valid_data_midpoint(ts,row_high,col_id);
        if(dec>0) return nodata;
        tlow=  ts.get_mydate()-this->time[row_low].get_mid().get_mydate();
        tges=  this->time[row_high].get_mid().get_mydate()-this->time[row_low].get_mid().get_mydate();
        yges1= val[col_id][row_high];
        yges2= val[col_id][row_low];
        yges=yges1-yges2  ;
        return yges2+tlow*yges/tges;
}

unsigned int  get_pos_of_corresponding_time_intervall(timestamp ts)
{

        unsigned int row,i;
        if (this->get_size()<1){
                err::err3("tempmap get_pos_of_corresponding_time_intervall: This tempmap is empty!");
                return this->get_size();
        }
        i=(int)this->get_size()/2;
        if (this->time[i].get_end()>ts)
        {
                for(row=0;row<=i;row++)
                {
                        if(this->time[row].contains(ts)) return row;
                }
        }	
        else
        {
                if((1+i)==this->get_size())
                {
                         err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
                         return this->get_size();
                }
                for(row=i+1;row<this->get_size();row++)
                {
                        if(this->time[row].contains(ts)) return row;
                }
        }
        err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
        return this->get_size();
}

unsigned int  get_pos_where_ts_bigger_than_this_start(timestamp ts)
{
        unsigned int row,i;
        if (this->get_size()<1){
                err::err3("tempmap get_pos_of_corresponding_time_intervall: This tempmap is empty!");
                return this->get_size();
        }
        i=(int)((this->get_size()-1)/2);
        if (this->time[i].get_end()>ts)
        {
                for(row=0;row<=i;row++)
                {
                        if(this->time[row].contains_plus_end(ts)) return row;
                }
        }	
        else
        {
                if((1+i)==this->get_size())
                {
                         err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
                         return this->get_size();
                }
                for(row=i+1;row<this->get_size();row++)
                {
                        if(this->time[row].contains_plus_end(ts)) return row;
                }
        }
        err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
        return this->get_size();
}

unsigned int  get_pos_where_ts_bigger_equal_than_this_start_but_not_end(timestamp ts)
{
        unsigned int row,i;
        if (this->get_size()<1){
                err::err3("tempmap get_pos_of_corresponding_time_intervall: This tempmap is empty!");
                return this->get_size();
        }
        i=(int)((this->get_size()-1)/2);
        if (this->time[i].get_end()>ts)
        {
                for(row=0;row<=i;row++)
                {
                        if(this->time[row].get_start()<=ts) return row;
                }
        }	
        else
        {
                if((1+i)==this->get_size())
                {
                         err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
                         return this->get_size();
                }
                for(row=i+1;row<this->get_size();row++)
                {
                        if((this->time[row].get_start()<=ts)&&(this->time[row].get_end()>ts)) return row;
                }
        }
        err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
        return this->get_size();
}

unsigned int  get_pos_where_ts_smaller_equal_than_this_end_but_not_this_start(timestamp ts)
{
        unsigned int row,i;
        if (this->get_size()<1){
                err::err3("tempmap get_pos_of_corresponding_time_intervall: This tempmap is empty!");
                return this->get_size();
        }
        i=(int)((this->get_size()-1)/2);
        if (this->time[i].get_end()>=ts)
        {
                for(row=i;row<=0;row++)
                {
                        if((this->time[row].get_start()<(ts))&&(this->time[row].get_end()>=ts)) return row;
                }
        }	
        else
        {
           
                if((1+i)==this->get_size())
                {
                         err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
                         return this->get_size();
                }
                for(row=i+1;row<this->get_size();row++)
                {
                         if((this->time[row].get_start()<(ts))&&(this->time[row].get_end()>=ts)) return row;
                }
        }
        err::err3("tempmap get_pos_of_corresponding_time_intervall:NOT FOUND");
        return this->get_size();
}
// high level gets

int get_aggregate_of_one_timeintervall_by_linear_interpolation(const time_intervall &ti,string kind,int minpoints,double boundary_constraint, 
        vector <pair <T,U> > &vec_val)
{ // if there is a time_intervall &ti this function returns a aggregated value from this tempmap for this given time intervall
        //string kind=(mean/sum) defines what type of aggregated information we want to have
        //int minpoints: is a constraint determining that the number of midpoints (tempmap) within in the intervall &ti must be at least minpoints;
        // double_boundary_constraint (0-1) if the time_intervall is at the very start or very end of this tempmap 
                //the timeperiod not covered by tempmap must be smaller than boundary_constraint*ti_duration
                // this tempmap:#----|-----|-------|---#" (|-> midpoint)
                // &ti:           #------#
        //&vec_val: contains the keys of variables for that aggregation has to be undertaken

        int dec=0;
        unsigned int row;
        unsigned int count;
        unsigned int start_pos_upper_mp,end_pos_lower_mp;
        unsigned int start_pos_lower_mp,end_pos_upper_mp;
        int real_minpoints;
        timestamp start= ti.get_start();
        timestamp end=ti.get_end();

        for(row=0;row<vec_val.size();row++){
                //1. condition of minpoints fullfilled?
                if(this->get_next_upeq_valid_data_midpoint(start,start_pos_upper_mp,vec_val[row].first)) dec++;
                if(this->get_next_loweq_valid_data_midpoint(end,end_pos_lower_mp,vec_val[row].first)) dec++;
                real_minpoints=this->get_number_of_valid_data_points(start_pos_upper_mp,end_pos_lower_mp,vec_val[row].first);
                if(real_minpoints<minpoints) dec++;
                if(dec>0) vec_val[row].second=nodata;
                else{
                        timepointmap <U> tpm(nulldata,nodata) ;
                        // left value
                        if (!(this->get_next_loweq_valid_data_midpoint(ti.get_start(),start_pos_lower_mp,vec_val[row].first))) // it exist a lower point
                                tpm.push_back(ti.get_start(),get_linear_interpolated_value_from_midpoints(start,vec_val[row].first));//tpm<-start values
                        else if((ti.get_start().get_dist(this->time[start_pos_upper_mp].get_mid()))<boundary_constraint*ti.get_dur()) //next upper value is within constraint
                                        tpm.push_back(ti.get_start(),this->val[vec_val[row].first][start_pos_upper_mp]);
                        else dec++;

                        // intermediate values
                        if(start_pos_upper_mp<=end_pos_lower_mp){
                                for(count=start_pos_upper_mp;count<=end_pos_lower_mp;count++)
                                        tpm.push_back(this->time[count].get_mid(),this->val[vec_val[row].first][count]);
                        }
                        //last value
                        if(!(this->get_next_upeq_valid_data_midpoint(ti.get_end(),end_pos_upper_mp,vec_val[row].first)))
                                tpm.push_back(ti.get_end(),get_linear_interpolated_value_from_midpoints(end,vec_val[row].first));
                        else if(this->time[end_pos_lower_mp].get_mid().get_dist(ti.get_end())<boundary_constraint*ti.get_dur())
                                tpm.push_back(ti.get_end(),this->val[vec_val[row].first][end_pos_lower_mp]);
                        else dec++;
                        // get aggregated value
                        if(dec>0) vec_val[row].second=nodata;
                        else {
                                if (kind=="sum") vec_val[row].second=tpm.get_integral_linear_interpolated(0,tpm.get_size());
                                else if(kind=="mean") vec_val[row].second=tpm.get_mean_linear_interpolated(0,tpm.get_size());
                                else err::err3 ("tempmap get_sum_of_one_timeintervall_by_linear_interpolation: kind is wrong defined (mean sum):"+kind);
                        }
                }

        }
        return 0;
}


U  get_sum(T id, time_intervall ti)
{
        return this->get_rate(id,ti)*  ti.get_dur();
}

U  get_rate(T id, time_intervall ti)
{
        // This method calculates the value of variable "id" for the time_intervaqll ti
        // We have three cases
        // 1. ti is identical to one time_intervall in this tempmap
        //		--> tempmap[id] will be returned (also nodata and nulldata)
        // 2. ti is completely covered by one time_intervall of this tempmap
        //		-->	 tempmap[id] will be returned (also nodata and nulldata)
        // 3. ti includes more than one time intervall of tempmap
        //		--> return of weighted_mean
        // 4. ti coveres two other time_intervalls of this tempmap
        //		--> return of weigted mean
        unsigned int row;
        double dur=0;
        double sum_dur=0;
        U zr;
        double sum_zr_x_dur=0;
        if((this->check_for_keys(id))){
                err::err3("tempmap_get_val_means:No such key in this tempmap");
                return nodata;
        }
        if (this->time.size()==0){
                err::err3("tempmap get_val_means: This tempmap is empty ");
                return nodata;
        }
        for (row=0;row<this->time.size();row++){
                zr=this->get_val(id,row);
                if(zr!=this->nodata) {
                        dur=this->time[row].get_dur_by_intersect(ti);
                        sum_zr_x_dur=sum_zr_x_dur+dur*zr;
                        sum_dur=sum_dur+dur;
                }
        }
        if (sum_dur==0) {
                err::err3("tempmap get_val_means: There is no intersection between time_intervall and this tempmap");
                return nodata;
        }
        return sum_zr_x_dur/sum_dur;

}
//info

int  check_for_keys(vector <T> keyvect) 
{
        //returns the number of matches beetween members in keyvect and tempmap.valkeys
        int dec=0;
        if((dec=Basics_map::check_for_keys(this->val,keyvect))<1){
                err::err3("tempmap check_for_keys: keys you want to have are not within tempmap");
                dec=0;
        }
        return dec;
}

int  check_for_keys(T key)
{
        //returns 0 for match and 1 for no match
        if(val.find(key)==val.end())return 1;
        return 0;
}

int  check_myself() 
 {
// same_size:
int dec=0;
typename map <T,vector<U> >::const_iterator colit;

for (colit=val.begin();colit!=val.end();colit++){
   if (colit->second.size()!=time.size()){
                        err::err3("tempmap check_for_consistency: Different size of entries");
                        dec++;
                }
}
// check for similar date
if(Basics_vector::check_for_similarities(this->time)!=0){
                err::err3("tempmap check_for_consistency: At least two overlapping time_intervalls");
                 dec++;
         }
// check for order
if(Basics_vector::check_for_ascending_order(this->time)){
                err::err3("tempmap check_for_consistency: entries not in ascending temporal order.");
                dec++;
         }
return dec;
}

int  check_for_gaps(unsigned int a, unsigned int b)
{  
        // checks if there are gaps between time intervalls 
        //input: start time intervall and end time intervall
        //output one if there are gaps or the  input is invalid
        //output zero if no gaps found
        unsigned int row;
        if (a==b) return 0;
        row=a;
        do
        {
                if (this->time[a].get_end()<this->time[a+1].get_start())return 1;
                row++;
        }	
        while(row<b);
        return 0;
}

int  check_for_overlaps(unsigned int a, unsigned int b)
{  
        // checks if there are gaps between time intervalls 
        //input: start time intervall and end time intervall
        //output one if there are gaps or the  input is invalid
        //output zero if no gaps found
        unsigned int row;
        if(a==b) return 0;

        row=a;
        do
        {
                if (this->time[a].get_end()>this->time[a+1].get_start())return 1;
                row++;
        }	
        while(row<b);
        return 0;
}
// point

int check_for_gaps_and_overlaps(unsigned int a, unsigned int b)
{
 return (check_for_gaps(a,b)||(check_for_overlaps(a,b)));
}

vector <time_intervall>*  point_time()
{
        return &time;
}

vector <U>*  point_val(T id)
{
        return &(val[id]);
}

map < T,vector< U > >*  point_val()
{
        return &(val);
}
};
//
//        
//        
//	tempmap(U inulldata,U inodata,string iintervall_mode, int imultipli,double idur);
//	tempmap(tempmap <T,U> *source);	
//	//tempmap(tempmap <T,string> *source);
//        tempmap();
//	
//	~tempmap();
//	
//	
//	//out
//	int print_in_file_simple_style_without_mydate(string root,string name,string suffix);	
//	int print_in_file_simple_style_with_mydate(string root,string name,string suffix) ;	
//	int print_in_file_start_end_style_without_mydate(string root,string name,string suffix);	
//	int print_in_file_start_end_style_with_mydate(string root,string name,string suffix) ;	
//	//set
//	int set_val(T id, unsigned int row, U value);	
//	int set_time_intervall(unsigned int row, time_intervall &source);	
//	int set_clear();	
//        int set_read_from_file(string root, string name,string suffix,string iintervallmode,int imultipli, double dur);
//	int set_order();
//        int push_back(int found,tempmap &cop);
//        int set_an_empty_tempmap(tempmap *source, vector<T> keys);  
//	int set_an_empty_tempmap(timestamp begin_date,timestamp end_date,double dur,vector<T> &val_id);	
//	int set_insert_a_row_entry (int row,tempmap <T,U> &source,int source_row,time_intervall timesubstitute);	
//	int set_insert_or_replace_entry(time_intervall tt,map<T,U> &source);	
//	int set_delete_a_row_entry(int row);	
//	int set_delete_rows_with_specific_value (U &delval);	
//	//int set_aggregate_by_linear_interp_from_tempmap(tempmap &source,string kind,double dur,int minpoints,double boundary_constraint,vector<T> &val_id)
//	int set_aggregate_by_linear_interp_from_tempmap( inp_tempmap_aggr *aggr);	
//	int set_key(T key);	
//	int set_delete_key(T key);	
//	int set_key (vector <T> keys);
//	int set_key_empty(T key);
//        int set_push_back_val(T key,time_intervall &ti,U wert);
//	//get
//	// primary gets
//	vector <T> get_valkeys();	
//	string get_intervallmode()	const;	
//	int get_multipli() const;	
//	double get_dur() const;	
//	timestamp get_start();	
//	timestamp get_end();
//        /**
//         * 
//         * @param a :pos of time intervall
//         * @return time_intervall //if a strange then error
//         */
//	time_intervall get_time_intervall(unsigned int a);
//        /**
//         * 
//         * @return last timeintervall if tempmap empty then error
//         */
//	time_intervall get_last_time_intervall();	
//	U get_val(T id, unsigned int row) ;	
//	U get_nodata ();
//        U get_nulldata();
//	unsigned int get_row_from_time_intervall (time_intervall &ti);	
//	unsigned int get_row_of_surrounding_time_intervall(time_intervall &ti);	
//	unsigned int get_size() const;	
//	int get_number_of_valid_data_points(const int a,const int b,const T id);	
//	// secondary gets
//	int get_number_of_midpoints_within_an_intervall(const time_intervall &ti);	
//	int get_pos_of_first_overlapping_intervall(time_intervall ti);	
//	int get_pos_of_last_overlapping_intervall(time_intervall ti);	
//	int get_next_loweq_valid_data_midpoint(const timestamp &ts,unsigned int &rowid,const T id);	
//	int get_next_upeq_valid_data_midpoint(const timestamp &ts,unsigned int &rowid,const T id);	
//	U get_linear_interpolated_value_from_midpoints(timestamp &ts,const T col_id);	
//	unsigned int get_pos_of_corresponding_time_intervall(timestamp ts);	
//	unsigned int get_pos_where_ts_bigger_than_this_start(timestamp ts);	
//        unsigned int get_pos_where_ts_bigger_equal_than_this_start_but_not_end(timestamp ts);
//        unsigned int get_pos_where_ts_smaller_equal_than_this_end_but_not_this_start(timestamp ts);
//	// high level gets	
//	int get_aggregate_of_one_timeintervall_by_linear_interpolation(const time_intervall &ti,string kind,int minpoints,double boundary_constraint, 
//		vector <pair <T,U> > &vec_val);
//	U get_sum(T id, time_intervall ti);	
//	U get_rate(T id, time_intervall ti);	
//        int check_for_keys(vector <T> keyvect) ;
//        /**
//         *@desc checks if key exists in this tempmap
//         *@desc returns 0 if key was found
//         *@desc otherwise 1
//         */
//	int check_for_keys(T key);	
//	int check_myself() ;
//	int check_for_gaps(unsigned int a, unsigned int b);	
//	int check_for_overlaps(unsigned int a, unsigned int b);	
//	// point
//	int check_for_gaps_and_overlaps(unsigned int a, unsigned int b);	
//	vector <time_intervall>* point_time();
//	vector <U>* point_val(T id);
//	map < T,vector< U > >* point_val();
//	
//};


template <class T,class U> class tempmap_loop
{
	protected:
	tempmap <T,U>*map;
	timestamp start;
	timestamp end;
	time_intervall recent_intervall;
	unsigned int recent_row;
	unsigned int end_row;
	unsigned int start_row;
	public:
	tempmap_loop(tempmap < T,U > *itempmap,timestamp &istart, timestamp &iend)
	{
                unsigned int last_row;
		map=itempmap;
		start=istart;
		end=iend;
		// Test if start <=end
		if	(start>end) {
			err::err3("tempmap_loop::tempmap_loop:Start>end");
			}
		//Test if start is within map
		if(map->get_start()>start){
			err::err3("tempmap_loop::tempmap_loop:start<map");
		}
		if(map->get_end()<end){
			err::err3("tempmap_loop::tempmap_loop:end>map");
		}
		this->start_row=recent_row=map->get_pos_of_corresponding_time_intervall(start);
		last_row=map->get_pos_where_ts_bigger_than_this_start(end);
		//Test for gaps
		if  (map->check_for_gaps_and_overlaps(recent_row,last_row)){
			err::err3("tempmap_loop::tempmap_loop:ti not completely covered, there are gaps or overlaps");
		}	
		recent_intervall.set(start, map->get_time_intervall(recent_row).get_end());
		
	}
	int set_next()
	{
		//1. Fall wir sind schon in der letzten row; neues Intervall nicht m�glich
		if(recent_row==end_row) return 1;
		//2. Fall wir sind kurz vor der letzten row
		if((recent_row+1)==end_row){
			recent_row=recent_row+1;
			recent_intervall.set(map->get_time_intervall(recent_row),end);
			return 0;
		}
		if ((recent_row+1)<end_row){
			recent_row=recent_row+1;
			recent_intervall.set(map->get_time_intervall(recent_row));
			return 0;
		}
	}
	time_intervall get_recent_intervall()
	{
		return recent_intervall;
	}
} ;
#endif	/* TEMPMAP_H */

